/*
 *
 * only support for "exact division"
 *
 *
 *
 */


#include <stdlib.h>
#include <stdio.h>
#include "slave.h"
#include "3d7p_aceMesh.h"
#include "task.h"
#include "ldm_malloc.h"
__thread_local volatile unsigned long get_reply;
__thread_local volatile unsigned long put_reply;
//kernel region
__thread_local_fix double A_lhs[BLKX][BLKY][BLKZ];
__thread_local_fix double A_rhs[BLKX][BLKY][BLKZ];
//up and down shade region
__thread_local_fix double A_us[BLKY][BLKZ];
__thread_local_fix double A_ds[BLKY][BLKZ];
//left and right shade  region
__thread_local_fix double A_ls[BLKX][BLKZ];
__thread_local_fix double A_rs[BLKX][BLKZ];
//front and back shade region
__thread_local_fix double A_fs[BLKX][BLKY];
__thread_local_fix double A_bs[BLKX][BLKY];
//Record the logical information of the last time executed task.
__thread_local_fix int last_iter,last_starti,last_startj,last_startk;
extern double A[2][SIZEX][SIZEY][SIZEZ];

#define alpha_d 0.0876
#define beta_d  0.0765

#ifdef _PROFILING
__thread_local int core_id=0;
__thread_local volatile unsigned long dma_start1,dma_end1,dma_start2,dma_end2,dma_start3,dma_end3,dma_start4,dma_end4;
__thread_local volatile unsigned long comp_start1,comp_end1,comp_start2,comp_end2;
extern unsigned long slave_comp_count[64];
extern unsigned long slave_dma_count[64];
unsigned long rtc_()
{
  unsigned long rpcc;
  asm volatile("rcsr  %0,4":"=r"(rpcc));
  return rpcc;
}
#endif

void stencil_core(targs* args)
{  
   //0. assumptions       
   //data region: [starti-1,endi] [startj-1,endj] [startk-1,endk]  
   //compute region: [starti, endi) [startj,endj) [startk,endk)
   int dest,src,i,j,k,s_iter,s_starti,s_endi,s_startj,s_endj,s_startk,s_endk;
   int len, bsize, stride;   
   int i_region,j_region,k_region;
   int i_i,j_j,k_k;
   int ii,jj,kk;
   core_id=athread_get_id(-1);
   s_iter = args->iter;
   dest = (s_iter) % 2 ;
   src = 1 - dest;
   s_starti = args->starti;
   s_endi = args->endi;
   s_startj = args->startj;
   s_endj = args->endj;
   s_startk = 1;
   s_endk = args->k_N-1;
   i_region = s_endi-s_starti-1;
   j_region = s_endj-s_startj-1;
   k_region = s_endk-s_startk-1;   
   i_i = s_endi-s_starti-2;
   j_j = s_endj-s_startj-2;
   k_k = s_endk-s_startk-2;
if((s_iter-1) == last_iter && s_starti == last_starti && s_startj == last_startj && s_startk == last_startk)
{
  stride = (SIZEZ-1)*8;
  len = BLKY*8;
  bsize = 8;
#ifdef _PROFILING
  dma_start1=rtc_();
#endif
  get_reply = 0;
  //1.1 update front and back shade data
 /* for(i = s_starti; i < s_endi; ++i )
  {
     athread_get(PE_MODE,&A[src][i][s_startj][s_startk-1]
                   , &A_fs[i-s_starti][0]
                   , len,(void*)&get_reply
                   , 0, stride, bsize);
     athread_get(PE_MODE,&A[src][i][s_startj][s_endk]
                   , &A_bs[i-s_starti][0]
                   , len,(void*)&get_reply
                   , 0, stride, bsize); 
  }*/
  //1.2 update up and down shade data
  stride = (SIZEZ-(BLKZ))*8;
  len = (BLKY)*(BLKZ)*8;
  bsize = (BLKZ)*8;
  athread_get(PE_MODE,&A[src][s_starti-1][s_startj][s_startk]
                 , &A_us[0][0]
                 , len, (void*)&get_reply
                 , 0, stride, bsize);
  athread_get(PE_MODE,&A[src][s_endi][s_startj][s_startk]
                 , &A_ds[0][0]
                 , len, (void*)&get_reply
                 , 0, stride, bsize);
  //1.3 update left and right shade data
  stride = ((SIZEY-1)*SIZEZ+(SIZEZ-(BLKZ)))*8;
  len = (BLKX)*(BLKZ)*8;
  bsize = (BLKZ)*8;
  athread_get(PE_MODE,&A[src][s_starti][s_startj-1][s_startk]
                   , &A_ls[0][0]
                   , len, (void*)&get_reply
                   , 0, stride, bsize);
  athread_get(PE_MODE,&A[src][s_starti][s_endj][s_startk]
                   , &A_rs[0][0]
                   , len,(void*)&get_reply
                   , 0, stride, bsize);    
  while(get_reply!=(4)); 
#ifdef _PROFILING
  dma_end1=rtc_();
  comp_start1=rtc_();
#endif
  //2.compute core data
/*  for(ii = 1; ii < i_region; ii++)
     for(jj = 1; jj < j_region; jj++)
        for(kk = 1; kk < k_region; kk++) 
            A_rhs[ii][jj][kk] = alpha_d * (A_lhs[ii][jj][kk]) + \
                     beta_d * (A_lhs[ii-1][jj][kk] + A_lhs[ii+1][jj][kk] +\
                     A_lhs[ii][jj-1][kk] + A_lhs[ii][jj+1][kk]+\
                    A_lhs[ii][jj][kk-1] + A_lhs[ii][jj][kk+1]);*/
    for(ii = 1; ii < i_region; ++ii)
       for(jj = 1; jj < j_region; ++jj)
         for(kk = 1; kk <(k_region-1)-(k_region-1)%4; kk+=4)
         {
            A_rhs[ii][jj][kk] = alpha_d * (A_lhs[ii][jj][kk]) + \
                     beta_d * (A_lhs[(ii-1)][jj][kk] + A_lhs[(ii+1)][jj][kk] +\
                     A_lhs[ii][jj-1][kk] + A_lhs[ii][(jj+1)][kk]+\
                     A_lhs[ii][jj][(kk-1)] + A_lhs[ii][jj][(kk+1)]);
            A_rhs[ii][jj][kk+1] = alpha_d * (A_lhs[ii][jj][kk+1]) + \
                     beta_d * (A_lhs[(ii-1)][jj][kk+1] + A_lhs[(ii+1)][jj][kk+1] +\
                     A_lhs[ii][jj-1][kk+1] + A_lhs[ii][(jj+1)][kk+1]+\
                     A_lhs[ii][jj][(kk)] + A_lhs[ii][jj][(kk+2)]);
            A_rhs[ii][jj][kk+2] = alpha_d * (A_lhs[ii][jj][kk+2]) + \
                     beta_d * (A_lhs[(ii-1)][jj][kk+2] + A_lhs[(ii+1)][jj][kk+2] +\
                     A_lhs[ii][jj-1][kk+2] + A_lhs[ii][(jj+1)][kk+2]+\
                     A_lhs[ii][jj][(kk+1)] + A_lhs[ii][jj][(kk+3)]);
            A_rhs[ii][jj][kk+3] = alpha_d * (A_lhs[ii][jj][kk+3]) + \
                     beta_d * (A_lhs[(ii-1)][jj][kk+3] + A_lhs[(ii+1)][jj][kk+3] +\
                     A_lhs[ii][jj-1][kk+3] + A_lhs[ii][(jj+1)][kk+3]+\
                     A_lhs[ii][jj][(kk+2)] + A_lhs[ii][jj][(kk+4)]);
         }
     for(ii = 1; ii < i_region; ++ii)
       for(jj = 1; jj < j_region; ++jj)
         for(kk = (k_region-1)-(k_region-1)%4; kk < k_region; kk+=1)
         {
            A_rhs[ii][jj][kk] = alpha_d * (A_lhs[ii][jj][kk]) + \
                     beta_d * (A_lhs[(ii-1)][jj][kk] + A_lhs[(ii+1)][jj][kk] +\
                     A_lhs[ii][jj-1][kk] + A_lhs[ii][(jj+1)][kk]+\
                     A_lhs[ii][jj][(kk-1)] + A_lhs[ii][jj][(kk+1)]);
         }
  //4 compute 4 line 4 face
  //4.1 compute up and down line of k dimensional change
  for(k = 1; k < k_region; ++k)
  {
    //left face
    A_rhs[0][0][k] = alpha_d * (A_lhs[0][0][k]) + \
                     beta_d * (A_us[0][k] + A_lhs[1][0][k] +\
                     A_ls[0][k] + A_lhs[0][1][k]+\
                     A_lhs[0][0][k-1] + A_lhs[0][0][k+1]);
    A_rhs[i_region][0][k] = alpha_d * (A_lhs[i_region][0][k]) + \
                     beta_d * (A_lhs[i_i][0][k] + A_ds[0][k] +\
                     A_ls[i_region][k] + A_lhs[i_region][1][k]+\
                     A_lhs[i_region][0][k-1]+ A_lhs[i_region][0][k+1]);
   //right face 
    A_rhs[0][j_region][k] = alpha_d * (A_lhs[0][j_region][k]) + \
                     beta_d * (A_us[j_region][k] + A_lhs[1][j_region][k] +\
                     A_lhs[0][j_j][k] + A_rs[0][k]+\
                     A_lhs[0][j_region][k-1] + A_lhs[0][j_region][k+1]);
    A_rhs[i_region][j_region][k] = alpha_d * (A_lhs[i_region][j_region][k]) + \
                     beta_d * (A_lhs[i_i][j_region][k] + A_ds[j_region][k] +\
                     A_lhs[i_region][j_j][k] + A_rs[i_region][k]+\
                     A_lhs[i_region][j_region][k-1] + A_lhs[i_region][j_region][k+1]);
  }  
  //4.2 compute left and right face
  for(i = 1; i < i_region; ++i)
    for(k = 1; k < k_region; ++k)
    {
       A_rhs[i][0][k] = alpha_d * (A_lhs[i][0][k]) + \
                     beta_d * (A_lhs[i-1][0][k] + A_lhs[i+1][0][k] +\
                     A_ls[i][k] + A_lhs[i][1][k]+\
                     A_lhs[i][0][k-1] + A_lhs[i][0][k+1]);
       A_rhs[i][j_region][k] = alpha_d * A_lhs[i][j_region][k] + \
                     beta_d * (A_lhs[i-1][j_region][k] + A_lhs[i+1][j_region][k] +\
                     A_lhs[i][j_j][k] + A_rs[i][k]+\
                     A_lhs[i][j_region][k-1] + A_lhs[i][j_region][k+1]);
    }
   // 4.3 compute up and down face
   for(j = 1; j < j_region; ++j)
    for(k = 1; k < k_region; ++k)
    {
      A_rhs[0][j][k] = alpha_d * A_lhs[0][j][k] + \
                     beta_d * (A_us[j][k] + A_lhs[1][j][k] +\
                     A_lhs[0][j-1][k] + A_lhs[0][j+1][k]+\
                     A_lhs[0][j][k-1] + A_lhs[0][j][k+1]);
      A_rhs[i_region][j][k] =  alpha_d * A_lhs[i_region][j][k] + \
                     beta_d * (A_lhs[i_i][j][k] + A_ds[j][k] +\
                     A_lhs[i_region][j-1][k] + A_lhs[i_region][j+1][k]+\
                     A_lhs[i_region][j][k-1] + A_lhs[i_region][j][k+1]);
   }
  //6. compute 8 corner point
  //6.1 compute up_left_front_point
  A_rhs[0][0][0] = alpha_d * A_lhs[0][0][0] + \
                   beta_d * (A_us[0][0] + A_lhs[1][0][0] +\
                   A_ls[0][0] + A_lhs[0][1][0]+\
                   A_fs[0][0] + A_lhs[0][0][1]); 
  //6.2 compute up_left_back_point
  A_rhs[0][0][k_region] = alpha_d * A_lhs[0][0][k_region] + \
                   beta_d * (A_us[0][k_region] +\
                   A_lhs[1][0][k_region] +\
                   A_ls[0][k_region] + A_lhs[0][1][k_region]+\
                   A_lhs[0][0][k_k] + A_bs[0][0]);
  
  //6.3 compute up_right_front_point
  A_rhs[0][j_region][0] = alpha_d * A_lhs[0][j_region][0] + \
                     beta_d * (A_us[j_region][0] +\
                     A_lhs[1][j_region][0] +\
                     A_lhs[0][j_j][0] + A_rs[0][0]+\
                     A_fs[0][j_region] + A_lhs[0][j_region][1]);
  //6.4 compute up_right_back_point
  A_rhs[0][j_region][k_region] = alpha_d * \
                    A_lhs[0][j_region][k_region]+ \
                     beta_d * (A_us[j_region][k_region] + \
                     A_lhs[1][j_region][k_region] + \
                     A_lhs[0][j_j][k_region] + \
                     A_rs[0][k_region]+\
                     A_lhs[0][j_region][k_k] + \
                     A_bs[0][j_region]);  
  //6.5 compute down_left_front_point
   A_rhs[i_region][0][0] =   alpha_d * A_lhs[i_region][0][0] + \
                     beta_d * (A_lhs[i_i][0][0] + A_ds[0][0] +\
                     A_ls[i_region][0] + A_lhs[i_region][1][0]+\
                     A_fs[i_region][0] + A_lhs[i_region][0][1]);  
  //6.6 compute down_left_back_point
   A_rhs[i_region][0][k_region] = alpha_d * \
                     A_lhs[i_region][0][k_region] + \
                     beta_d * (A_lhs[i_i][0][k_region] + \
                     A_ds[0][k_region] +\
                     A_ls[i_region][k_region] +\
                     A_lhs[i_region][1][k_region]+\
                     A_lhs[i_region][0][k_k] +\
                     A_bs[i_region][0]);    
  //6.7 compute down_right_front_point
  A_rhs[i_region][j_region][0] = alpha_d * \
                     A_lhs[i_region][j_region][0] + \
                     beta_d * (A_lhs[i_i][j_region][0] + \
                     A_ds[j_region][0] + \
                     A_lhs[i_region][j_j][0] + \
                     A_rs[i_region][0]+ \
                     A_fs[i_region][j_region] + \
                     A_lhs[i_region][j_region][1]); 
  //6.8  compute down_right_back_point
  A_rhs[i_region][j_region][k_region] = alpha_d * \
                     A_lhs[i_region][j_region][k_region] + \
                     beta_d * (A_lhs[i_i][j_region][k_region] + \
                     A_ds[j_region][k_region] + \
                     A_lhs[i_region][j_j][k_region] + \
                     A_rs[i_region][k_region]+ \
                     A_lhs[i_region][j_region][k_k] + \
                     A_bs[i_region][j_region]); 
 //7 compute 8 line data
  //7.1 compute up and down line of j dimensional  change 
  for(j = 1;j < j_region; ++j)
  {
  //front face
    A_rhs[0][j][0] = alpha_d * A_lhs[0][j][0]+ \
                     beta_d * (A_us[j][0] + A_lhs[1][j][0] +\
                     A_lhs[0][j-1][0] + A_lhs[0][j+1][0]+\
                     A_fs[0][j] + A_lhs[0][j][1]);
    A_rhs[i_region][j][0] = alpha_d * A_lhs[i_region][j][0] + \
                     beta_d * (A_lhs[i_i][j][0] + A_ds[j][0] +\
                     A_lhs[i_region][j-1][0] + A_lhs[i_region][j+1][0]+\
                     A_fs[i_region][j] + A_lhs[i_region][j][1]);
  //back face
    A_rhs[0][j][k_region] = alpha_d * A_lhs[0][j][k_region] + \
                     beta_d * (A_us[j][k_region] + A_lhs[1][j][k_region] +\
                     A_lhs[0][j-1][k_region] + A_lhs[0][j+1][k_region]+\
                     A_lhs[0][j][k_k] + A_bs[0][j]);
    A_rhs[i_region][j][k_region] =  alpha_d * A_lhs[i_region][j][k_region] + \
                     beta_d * (A_lhs[i_i][j][k_region] + A_ds[j][k_region] +\
                     A_lhs[i_region][j-1][k_region] + A_lhs[i_region][j+1][k_region]+\
                     A_lhs[i_region][j][k_k] + A_bs[i_region][j]);
  }
  //7.2 compute left and right line of i dimensional change
  for(i = 1;i < i_region; ++i)
  {
   //front face
    A_rhs[i][0][0] = alpha_d * A_lhs[i][0][0] + \
                     beta_d * (A_lhs[i-1][0][0] + A_lhs[i+1][0][0] +\
                     A_ls[i][0] + A_lhs[i][1][0]+\
                     A_fs[i][0] + A_lhs[i][0][1]);
    A_rhs[i][j_region][0] = alpha_d * A_lhs[i][j_region][0] + \
                     beta_d * (A_lhs[i-1][j_region][0] + A_lhs[i+1][j_region][0] +\
                     A_lhs[i][j_j][0] + A_rs[i][0]+\
                     A_fs[i][j_region] + A_lhs[i][j_region][1]); 
  //back face 
    A_rhs[i][0][k_region] = alpha_d * A_lhs[i][0][k_region] + \
                     beta_d * (A_lhs[i-1][0][k_region] + A_lhs[i+1][0][k_region] +\
                     A_ls[i][k_region] + A_lhs[i][1][k_region]+\
                     A_lhs[i][0][k_k] + A_bs[i][0]); 
    A_rhs[i][j_region][k_region] = alpha_d * A_lhs[i][j_region][k_region] + \
                     beta_d * (A_lhs[i-1][j_region][k_region] + A_lhs[i+1][j_region][k_region] +\
                     A_lhs[i][j_j][k_region] + A_rs[i][k_region]+\
                     A_lhs[i][j_region][k_k] + A_bs[i][j_region]);
  }
  //8 compute 2 face
  //8.1 compute front and back face 
  for(i = 1; i < i_region; ++i)
    for(j = 1; j < j_region; ++j)
    {
       A_rhs[i][j][0] = alpha_d * A_lhs[i][j][0] + \
                     beta_d * (A_lhs[i-1][j][0] + A_lhs[i+1][j][0] +\
                     A_lhs[i][j-1][0] + A_lhs[i][j+1][0]+\
                     A_fs[i][j] + A_lhs[i][j][1]); 
       A_rhs[i][j][k_region] = alpha_d * A_lhs[i][j][k_region] + \
                     beta_d * (A_lhs[i-1][j][k_region] + A_lhs[i+1][j][k_region] +\
                     A_lhs[i][j-1][k_region] + A_lhs[i][j+1][k_region]+\
                     A_lhs[i][j][k_k] + A_bs[i][j]);  
    }
#ifdef _PROFILING
  comp_end1=rtc_();
#endif
  //9 write back   
   stride = (SIZEZ-(BLKZ))*8;
   bsize = (BLKZ)*8;
   len = bsize*(BLKY);
#ifdef _PROFILING
  dma_start2=rtc_();
#endif
   put_reply=0;
   for(i =  s_starti; i < s_endi; ++i)
     athread_put(PE_MODE,&A_rhs[i-s_starti][0][0]
                     , &A[dest][i][s_startj][s_startk]
                     ,len,(void*)&put_reply,stride,bsize);
   while(put_reply!=(BLKX)); 
#ifdef _PROFILING
  dma_end2=rtc_();
#endif
}else{
//no reuse ldm
  //1 update core data
  bsize=(BLKZ)*8;
  stride=(SIZEZ-(BLKZ))*8;  //stride: from blocktail to blockhead 
  len= bsize*(BLKY);
#ifdef _PROFILING
  dma_start3=rtc_();
#endif
  get_reply=0;
  for(i = s_starti; i < s_endi; i++)
       athread_get(PE_MODE,&A[src][i][s_startj][s_startk]
                 , &A_rhs[i-s_starti][0][0]
                 , len, (void*)&get_reply
                 , 0, stride, bsize);
  //2 update front and back shade data
  stride = (SIZEZ-1)*8;
  len = (BLKY)*8;
  bsize = 8;
  for(i = s_starti; i < s_endi; ++i )
  {
     athread_get(PE_MODE,&A[src][i][s_startj][s_startk-1]
                   , &A_fs[i-s_starti][0]
                   , len,(void*)&get_reply
                   , 0, stride, bsize);
     athread_get(PE_MODE,&A[src][i][s_startj][s_endk]
                   , &A_bs[i-s_starti][0]
                   , len,(void*)&get_reply
                   , 0, stride, bsize); 
  }
  //3 update up and down shade data
  stride = (SIZEZ-(BLKZ))*8;
  len = (BLKY)*(BLKZ)*8;
  bsize = (BLKZ)*8;
  athread_get(PE_MODE,&A[src][s_starti-1][s_startj][s_startk]
                 , &A_us[0][0]
                 , len,(void*) &get_reply
                 , 0, stride, bsize);
  athread_get(PE_MODE,&A[src][s_endi][s_startj][s_startk]
                 , &A_ds[0][0]
                 , len, (void*)&get_reply
                 , 0, stride, bsize);
  //4 update left and right shade data
  stride = ((SIZEY-1)*SIZEZ+(SIZEZ-(BLKZ)))*8;
  len = (BLKX)*(BLKZ)*8;
  bsize = (BLKZ)*8;
  athread_get(PE_MODE,&A[src][s_starti][s_startj-1][s_startk]
                   , &A_ls[0][0]
                   , len, (void*)&get_reply
                   , 0, stride, bsize);
  athread_get(PE_MODE,&A[src][s_starti][s_endj][s_startk]
                   , &A_rs[0][0]
                   , len,(void*)&get_reply
                   , 0, stride, bsize);  
  while(get_reply!=(4+2*BLKX+BLKX));
#ifdef _PROFILING
  dma_end3=rtc_();
  comp_start2=rtc_();
#endif
   //5.compute core data
   /*for(ii = 1; ii < i_region; ii++)
     for(jj = 1; jj < j_region; jj++)
        for(kk = 1; kk < k_region; kk++)
            A_lhs[ii][jj][kk] = alpha_d * A_rhs[ii][jj][kk] + \
                     beta_d * (A_rhs[ii-1][jj][kk] + A_rhs[ii+1][jj][kk] +\
                     A_rhs[ii][jj-1][kk] + A_rhs[ii][jj+1][kk]+\
                     A_rhs[ii][jj][kk-1] + A_rhs[ii][jj][kk+1]);*/
  for(ii = 1; ii < i_region; ++ii)
       for(jj = 1; jj < j_region; ++jj)
         for(kk = 1; kk < (k_region-1)-(k_region-1)%4; kk+=4)
         {
            A_lhs[ii][jj][kk] = alpha_d * (A_rhs[ii][jj][kk]) + \
                     beta_d * (A_rhs[(ii-1)][jj][kk] + A_rhs[(ii+1)][jj][kk] +\
                     A_rhs[ii][jj-1][kk] + A_rhs[ii][(jj+1)][kk]+\
                     A_rhs[ii][jj][(kk-1)] + A_rhs[ii][jj][(kk+1)]);
            A_lhs[ii][jj][kk+1] = alpha_d * (A_rhs[ii][jj][kk+1]) + \
                     beta_d * (A_rhs[(ii-1)][jj][kk+1] + A_rhs[(ii+1)][jj][kk+1] +\
                     A_rhs[ii][jj-1][kk+1] + A_rhs[ii][(jj+1)][kk+1]+\
                     A_rhs[ii][jj][(kk)] + A_rhs[ii][jj][(kk+2)]);
            A_lhs[ii][jj][kk+2] = alpha_d * (A_rhs[ii][jj][kk+2]) + \
                     beta_d * (A_rhs[(ii-1)][jj][kk+2] + A_rhs[(ii+1)][jj][kk+2] +\
                     A_rhs[ii][jj-1][kk+2] + A_rhs[ii][(jj+1)][kk+2]+\
                     A_rhs[ii][jj][(kk+1)] + A_rhs[ii][jj][(kk+3)]);
            A_lhs[ii][jj][kk+3] = alpha_d * (A_rhs[ii][jj][kk+3]) + \
                     beta_d * (A_rhs[(ii-1)][jj][kk+3] + A_rhs[(ii+1)][jj][kk+3] +\
                     A_rhs[ii][jj-1][kk+3] + A_rhs[ii][(jj+1)][kk+3]+\
                     A_rhs[ii][jj][(kk+2)] + A_rhs[ii][jj][(kk+4)]);
         }
     for(ii = 1; ii < i_region; ++ii)
       for(jj = 1; jj < j_region; ++jj)
         for(kk = (k_region-1)-(k_region-1)%4; kk < k_region; kk+=1)
         {
            A_lhs[ii][jj][kk] = alpha_d * (A_rhs[ii][jj][kk]) + \
                     beta_d * (A_rhs[(ii-1)][jj][kk] + A_rhs[(ii+1)][jj][kk] +\
                     A_rhs[ii][jj-1][kk] + A_rhs[ii][(jj+1)][kk]+\
                     A_rhs[ii][jj][(kk-1)] + A_rhs[ii][jj][(kk+1)]);
         }
  //6.compute 4 lines, 4 faces.
  //6.1 compute up and down line of k dimensional change
  for(kk = 1; kk < k_region; ++kk)
  {
    //left face
    A_lhs[0][0][kk] = alpha_d * A_rhs[0][0][kk] + \
                     beta_d * (A_us[0][kk] + A_rhs[1][0][kk] +\
                     A_ls[0][kk] + A_rhs[0][1][kk]+\
                     A_rhs[0][0][kk-1] + A_rhs[0][0][kk+1]);
    A_lhs[i_region][0][kk] = alpha_d * A_rhs[i_region][0][kk]+ \
                     beta_d * (A_rhs[i_i][0][kk] + A_ds[0][kk] +\
                     A_ls[i_region][kk] + A_rhs[i_region][1][kk]+\
                     A_rhs[i_region][0][kk-1]+ A_rhs[i_region][0][kk+1]);
   //right face 
    A_lhs[0][j_region][kk] = alpha_d * A_rhs[0][j_region][kk]+ \
                     beta_d * (A_us[j_region][kk] + A_rhs[1][j_region][kk] +\
                     A_rhs[0][j_j][kk] + A_rs[0][kk]+\
                     A_rhs[0][j_region][kk-1] + A_rhs[0][j_region][kk+1]);
    A_lhs[i_region][j_region][kk] = alpha_d * A_rhs[i_region][j_region][kk] + \
                     beta_d * (A_rhs[i_i][j_region][kk] + A_ds[j_region][kk] +\
                     A_rhs[i_region][j_j][kk] + A_rs[i_region][kk]+\
                     A_rhs[i_region][j_region][kk-1] + A_rhs[i_region][j_region][kk+1]);
  }
  //6.2 compute left and right face 
   for(ii = 1; ii < i_region; ++ii)
    for(kk = 1; kk < k_region; ++kk)
    {
       A_lhs[ii][0][kk] = alpha_d * A_rhs[ii][0][kk] + \
                     beta_d * (A_rhs[ii-1][0][kk] + A_rhs[ii+1][0][kk] +\
                     A_ls[ii][kk] + A_rhs[ii][1][kk]+\
                     A_rhs[ii][0][kk-1] + A_rhs[ii][0][kk+1]);
       A_lhs[ii][j_region][kk] = alpha_d * A_rhs[ii][j_region][kk] + \
                     beta_d * (A_rhs[ii-1][j_region][kk] + A_rhs[ii+1][j_region][kk] +\
                     A_rhs[ii][j_j][kk] + A_rs[ii][kk]+\
                     A_rhs[ii][j_region][kk-1] + A_rhs[ii][j_region][kk+1]);
    }
   // 6.3 compute up and down face
    for(j = 1; j < j_region; ++j)
    for(k = 1; k < k_region; ++k)
    {
      A_lhs[0][j][k] = alpha_d * A_rhs[0][j][k]+ \
                     beta_d * (A_us[j][k] + A_rhs[1][j][k] +\
                     A_rhs[0][j-1][k] + A_rhs[0][j+1][k]+\
                     A_rhs[0][j][k-1] + A_rhs[0][j][k+1]);
      A_lhs[i_region][j][k] =  alpha_d * A_rhs[i_region][j][k] + \
                     beta_d * (A_rhs[i_i][j][k] + A_ds[j][k] +\
                     A_rhs[i_region][j-1][k] + A_rhs[i_region][j+1][k]+\
                     A_rhs[i_region][j][k-1] + A_rhs[i_region][j][k+1]);
   }
  //7 compute 8 corner point
  //7.1 compute up_left_front_point
  A_lhs[0][0][0] = alpha_d * A_rhs[0][0][0] + \
                   beta_d * (A_us[0][0] + A_rhs[1][0][0] +\
                   A_ls[0][0] + A_rhs[0][1][0]+\
                   A_fs[0][0] + A_rhs[0][0][1]); 
  //7.2 compute up_left_back_point
  A_lhs[0][0][k_region] = alpha_d * A_rhs[0][0][k_region]+ \
                   beta_d * (A_us[0][k_region] +\
                   A_rhs[1][0][k_region] +\
                   A_ls[0][k_region] + A_rhs[0][1][k_region]+\
                   A_rhs[0][0][k_k] + A_bs[0][0]);
  
  //7.3 compute up_right_front_point
  A_lhs[0][j_region][0] = alpha_d * A_rhs[0][j_region][0]+ \
                     beta_d * (A_us[j_region][0] +\
                     A_rhs[1][j_region][0] +\
                     A_rhs[0][j_j][0] + A_rs[0][0]+\
                     A_fs[0][j_region] + A_rhs[0][j_region][1]);
  
  //7.4 compute up_right_back_point
  A_lhs[0][j_region][k_region] = alpha_d * \
                    A_rhs[0][j_region][k_region]+ \
                     beta_d * (A_us[j_region][k_region] + \
                     A_rhs[1][j_region][k_region] + \
                     A_rhs[0][j_j][k_region] + \
                     A_rs[0][k_region]+\
                     A_rhs[0][j_region][k_k] + \
                     A_bs[0][j_region]);  
  //7.5 compute down_left_front_point
   A_lhs[i_region][0][0] =   alpha_d * A_rhs[i_region][0][0] + \
                     beta_d * (A_rhs[i_i][0][0] + A_ds[0][0] +\
                     A_ls[i_region][0] + A_rhs[i_region][1][0]+\
                     A_fs[i_region][0] + A_rhs[i_region][0][1]);  
  //7.6 compute down_left_back_point
   A_lhs[i_region][0][k_region] = alpha_d * \
                     A_rhs[i_region][0][k_region] + \
                     beta_d * (A_rhs[i_i][0][k_region] + \
                     A_ds[0][k_region] +\
                     A_ls[i_region][k_region] +\
                     A_rhs[i_region][1][k_region]+\
                     A_rhs[i_region][0][k_k] +\
                     A_bs[i_region][0]);    
  //7.7 compute down_right_front_point
  A_lhs[i_region][j_region][0] = alpha_d * \
                     A_rhs[i_region][j_region][0] + \
                     beta_d * (A_rhs[i_i][j_region][0] + \
                     A_ds[j_region][0] + \
                     A_rhs[i_region][j_j][0] + \
                     A_rs[i_region][0]+ \
                     A_fs[i_region][j_region] + \
                     A_rhs[i_region][j_region][1]); 
  //7.8  compute down_right_back_point
  A_lhs[i_region][j_region][k_region] = alpha_d * \
                     A_rhs[i_region][j_region][k_region] + \
                     beta_d * (A_rhs[i_i][j_region][k_region] + \
                     A_ds[j_region][k_region] + \
                     A_rhs[i_region][j_j][k_region] + \
                     A_rs[i_region][k_region]+ \
                     A_rhs[i_region][j_region][k_k] + \
                     A_bs[i_region][j_region]); 
 //8 compute 8 line data
  //8.1 compute up and down line of j dimensional  change 
  for(j = 1;j < j_region; ++j)
  {
  //front face
    A_lhs[0][j][0] = alpha_d * A_rhs[0][j][0] + \
                     beta_d * (A_us[j][0] + A_rhs[1][j][0] +\
                     A_rhs[0][j-1][0] + A_rhs[0][j+1][0]+\
                     A_fs[0][j] + A_rhs[0][j][1]);
    A_lhs[i_region][j][0] = alpha_d * A_rhs[i_region][j][0] + \
                     beta_d * (A_rhs[i_i][j][0] + A_ds[j][0] +\
                     A_rhs[i_region][j-1][0] + A_rhs[i_region][j+1][0]+\
                     A_fs[i_region][j] + A_rhs[i_region][j][1]);
  //back face
    A_lhs[0][j][k_region] = alpha_d * A_rhs[0][j][k_region] + \
                     beta_d * (A_us[j][k_region] + A_rhs[1][j][k_region] +\
                     A_rhs[0][j-1][k_region] + A_rhs[0][j+1][k_region]+\
                     A_rhs[0][j][k_k] + A_bs[0][j]);
    A_lhs[i_region][j][k_region] =  alpha_d * A_rhs[i_region][j][k_region] + \
                     beta_d * (A_rhs[i_i][j][k_region] + A_ds[j][k_region] +\
                     A_rhs[i_region][j-1][k_region] + A_rhs[i_region][j+1][k_region]+\
                     A_rhs[i_region][j][k_k] + A_bs[i_region][j]);
  }
  //8.2 compute left and right line of i dimensional change
  for(i = 1;i < i_region; ++i)
  {
   //front face
    A_lhs[i][0][0] = alpha_d * A_rhs[i][0][0] + \
                     beta_d * (A_rhs[i-1][0][0] + A_rhs[i+1][0][0] +\
                     A_ls[i][0] + A_rhs[i][1][0]+\
                     A_fs[i][0] + A_rhs[i][0][1]);
    A_lhs[i][j_region][0] = alpha_d * (A_rhs[i][j_region][0]) + \
                     beta_d * (A_rhs[i-1][j_region][0] + A_rhs[i+1][j_region][0] +\
                     A_rhs[i][j_j][0] + A_rs[i][0]+\
                     A_fs[i][j_region] + A_rhs[i][j_region][1]); 
  //back face 
    A_lhs[i][0][k_region] = alpha_d * A_rhs[i][0][k_region] + \
                     beta_d * (A_rhs[i-1][0][k_region] + A_rhs[i+1][0][k_region] +\
                     A_ls[i][k_region] + A_rhs[i][1][k_region]+\
                     A_rhs[i][0][k_k] + A_bs[i][0]); 
    A_lhs[i][j_region][k_region] = alpha_d * A_rhs[i][j_region][k_region] + \
                     beta_d * (A_rhs[i-1][j_region][k_region] + A_rhs[i+1][j_region][k_region] +\
                     A_rhs[i][j_j][k_region] + A_rs[i][k_region]+\
                     A_rhs[i][j_region][k_k] + A_bs[i][j_region]);
  }
  // 9 compute 2 face
  //9.1 compute front and back face 
  for(i = 1; i < i_region; ++i)
    for(j = 1; j < j_region; ++j)
    {
       A_lhs[i][j][0] = alpha_d * A_rhs[i][j][0] + \
                     beta_d * (A_rhs[i-1][j][0] + A_rhs[i+1][j][0] +\
                     A_rhs[i][j-1][0] + A_rhs[i][j+1][0]+\
                     A_fs[i][j] + A_rhs[i][j][1]); 
       A_lhs[i][j][k_region] = alpha_d * A_rhs[i][j][k_region] + \
                     beta_d * (A_rhs[i-1][j][k_region] + A_rhs[i+1][j][k_region] +\
                     A_rhs[i][j-1][k_region] + A_rhs[i][j+1][k_region]+\
                     A_rhs[i][j][k_k] + A_bs[i][j]);  
    }
#ifdef _PROFILING
  comp_end2=rtc_();
  slave_comp_count[core_id]+=((comp_end1-comp_start1)+(comp_end2-comp_start2));
#endif
  //10 write back
   stride = (SIZEZ-(BLKZ))*8;
   bsize = (BLKZ)*8;
   len = bsize*(BLKY);
#ifdef _PROFILING
  dma_start4=rtc_();
#endif
   put_reply=0;
   for(i =  s_starti; i < s_endi; ++i)
     athread_put(PE_MODE,&A_lhs[i-s_starti][0][0]
                     , &A[dest][i][s_startj][s_startk]
                     ,len,(void*)&put_reply,stride,bsize);
   while(put_reply!=(BLKX)); 
#ifdef _PROFILING
   dma_end4=rtc_();
   slave_dma_count[core_id]+=((dma_end1-dma_start1)+(dma_end2-dma_start2)+(dma_end3-dma_start3)+(dma_end4-dma_start4));
#endif
   last_iter = s_iter;
   last_starti = s_starti;
   last_startj = s_startj;
   last_startk = s_startk;
}
   
}
